package SGEngine

import (
	"container/list"
	//"fmt"
	"github.com/glfw"
)

const (
	EVENT_TYPE_SIZE = 7

	EVENT_CLICK      = 0
	EVENT_MOUSEMOVE  = 1
	EVENT_WINRESIZE  = 2
	EVENT_MOUSRENTER = 3
	EVENT_MOUSELEAVE = 4
	EVENT_MOUSEDOWN  = 5
	EVENT_MOUSEUP    = 6
)

const (
	//0000 0000 0000 0001
	EVENT_STATE_INNODE = 1 //鼠标光标在Node中
	//0000 0000 0000 0010
	EVENT_STATE_MOUSEDOWN = 1 << 1 //IS MouseDown
)

type EventCallFunc func(int, int, *EventNode)
type GetRectFunc func(INode, Vec3, Vec3) *Rect

type EventNode struct {
	Mnode        INode
	RegisterFunc []EventCallFunc
	NodeState    int32
}

var (
	EventList *list.List
)

func init() {
	EventList = list.New()
}

func RegisterEvent(node INode, _type int, Func EventCallFunc) {
	oldE := _FindEventNodeByINode(node)
	if oldE == nil {
		EN := new(EventNode)
		EN.Mnode = node
		EN.RegisterFunc = make([]EventCallFunc, EVENT_TYPE_SIZE)
		EN.RegisterFunc[_type] = Func
		EventList.PushBack(EN)
	} else {
		oldE.RegisterFunc[_type] = Func
	}
}

func _FindEventNodeByINode(inode INode) *EventNode {
	for e := EventList.Front(); e != nil; e = e.Next() {
		en := e.Value.(*EventNode)
		if en.Mnode == inode {
			return en
		}
	}
	return nil
}

func OnMouseClick(button, state int) {
	//mouse down
	X, Y := glfw.MousePos()
	for e := EventList.Front(); e != nil; e = e.Next() {
		if state == 1 {
			MouseDownDispatch(X, Y, e.Value.(*EventNode))
		} else {
			MouseUpDispatch(X, Y, e.Value.(*EventNode))
		}
	}
}

func OnWinReSize(width, height int) {

}

func OnMouseMove(X, Y int) {

	for e := EventList.Front(); e != nil; e = e.Next() {
		//mouse move
		if e.Value.(*EventNode).RegisterFunc[EVENT_MOUSEMOVE] != nil {
			e.Value.(*EventNode).RegisterFunc[EVENT_MOUSEMOVE](X, Y, e.Value.(*EventNode))
		}
		//mouse enter
		MouseEnterDispatch(X, Y, e.Value.(*EventNode))
		//mouse leave
		MouseLeaveDispatch(X, Y, e.Value.(*EventNode))
	}

}

func MouseEnterDispatch(X int, Y int, eh *EventNode) {
	if (eh.NodeState&EVENT_STATE_INNODE) == 0 && NodeIsInPos(eh.Mnode, X, Y) {
		if eh.RegisterFunc[EVENT_MOUSRENTER] != nil {
			eh.RegisterFunc[EVENT_MOUSRENTER](X, Y, eh)
		}
		eh.NodeState = eh.NodeState | EVENT_MOUSRENTER
	}
}

func MouseLeaveDispatch(X int, Y int, eh *EventNode) {
	if (eh.NodeState&EVENT_STATE_INNODE) >= 1 && !NodeIsInPos(eh.Mnode, X, Y) {
		if eh.RegisterFunc[EVENT_MOUSELEAVE] != nil {
			eh.RegisterFunc[EVENT_MOUSELEAVE](X, Y, eh)
		}
		eh.NodeState = eh.NodeState & 0xfffe
	}
}

func MouseDownDispatch(X int, Y int, eh *EventNode) {
	if NodeIsInPos(eh.Mnode, X, Y) {
		eh.NodeState = eh.NodeState | EVENT_STATE_MOUSEDOWN
		if eh.RegisterFunc[EVENT_MOUSEDOWN] != nil {
			eh.RegisterFunc[EVENT_MOUSEDOWN](X, Y, eh)

		}
	}
}

func MouseUpDispatch(X int, Y int, eh *EventNode) {
	if (eh.NodeState & EVENT_STATE_MOUSEDOWN) >= 1 {

		eh.NodeState = eh.NodeState & 0xfffd
		if NodeIsInPos(eh.Mnode, X, Y) {
			MouseClickDispatch(X, Y, eh)
		}
		if eh.RegisterFunc[EVENT_MOUSEUP] != nil {
			eh.RegisterFunc[EVENT_MOUSEUP](X, Y, eh)

		}
	}

}

func MouseClickDispatch(X int, Y int, eh *EventNode) {
	if eh.RegisterFunc[EVENT_CLICK] != nil {
		eh.RegisterFunc[EVENT_CLICK](X, Y, eh)
	}
}

func NodeIsInPos(node INode, X, Y int) bool {
	R := node.GetRect(node, node.GetTransfrom().ToWorldScale(), node.GetTransfrom().ToWorldPostion())
	xf := float64(X) - WinRoot.MainScene.Size().X*0.5
	yf := float64(Y) - WinRoot.MainScene.Size().Y*0.5
	yf *= -1
	if float64(xf) < R.MaxX && float64(xf) > R.MinX && float64(yf) < R.MaxY && float64(yf) > R.MinY {
		return true
	}
	return false
}
